package com.blockmeta.bbs.businesslibrary.net.rxjava;

import android.text.TextUtils;

import com.blockmeta.bbs.businesslibrary.net.pojo.BaseCodeResponse;
import com.blockmeta.bbs.businesslibrary.net.pojo.BaseImResponse;

import org.reactivestreams.Publisher;

import java.util.concurrent.TimeUnit;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableEmitter;
import io.reactivex.FlowableOnSubscribe;
import io.reactivex.FlowableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;


/**
 * @author airthor
 * date   2019/3/26
 */

public class RxUtil {
    /**
     * 简化线程操作
     */
    public static <T> FlowableTransformer<T, T> rxSchedulerHelper() {
        return new FlowableTransformer<T, T>() {
            @Override
            public Flowable<T> apply(Flowable<T> observable) {
                return observable.subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }

    /**
     * 统一返回结果处理
     * 如果返回结果没有data字段，需要抛出错误，createFlowable不允许传null,如果没有返回data的接口不能调这个方法
     * @param <T>
     * @return
     */
    public static <T> FlowableTransformer<BaseImResponse<T>, T> commonResult() {   //compose判断结果
        return new FlowableTransformer<BaseImResponse<T>, T>() {
            @Override
            public Flowable<T> apply(Flowable<BaseImResponse<T>> commonResponseFlowable) {
                return commonResponseFlowable.flatMap(new Function<BaseImResponse<T>, Flowable<T>>() {
                    @Override
                    public Flowable<T> apply(BaseImResponse<T> tBaseCodeResponse) {
                        if("200".equals(tBaseCodeResponse.code) && tBaseCodeResponse.data != null) {
                            return createFlowable(tBaseCodeResponse.data);
                        } else {
                            return Flowable.error(new CustomException(tBaseCodeResponse.code,tBaseCodeResponse.msg));
                        }
                    }
                });
            }
        };
    }


//    /**
//     * 统一返回结果处理
//     * 当data为空的时候调用，这样可以统一业务code的处理
//     * @param <T>
//     * @return
//     */
    public static <T> FlowableTransformer<BaseImResponse<T>, BaseImResponse<T>> dataNullResult() {   //compose判断结果
        return new FlowableTransformer<BaseImResponse<T>, BaseImResponse<T>>() {

            @Override
            public Flowable<BaseImResponse<T>> apply(Flowable<BaseImResponse<T>> commonResponseFlowable) {

                return commonResponseFlowable.flatMap(new Function<BaseImResponse<T>, Flowable<BaseImResponse<T>>>() {
                    @Override
                    public Flowable<BaseImResponse<T>> apply(BaseImResponse<T> tBaseImResponse) throws Exception {
                        if("200".equals(tBaseImResponse.code)){
                            return createFlowable(tBaseImResponse);
                        }else {
                            return Flowable.error(new CustomException(tBaseImResponse.code, tBaseImResponse.msg));
                        }
                    }
                });
            }
        };
    }

    /**
     *
     * 如果返回结果没有data字段，需要抛出错误，createFlowable不允许传null,如果没有返回data的接口不能调这个方法
     * @param <T>
     * @return
     */
    public static <T> FlowableTransformer<BaseCodeResponse<T>,T> commonResultByCode(){
        return new FlowableTransformer<BaseCodeResponse<T>, T>() {
            @Override
            public Publisher<T> apply(Flowable<BaseCodeResponse<T>> baseCodeResponseFlowable) {
                return baseCodeResponseFlowable.flatMap(new Function<BaseCodeResponse<T>, Flowable<T>>() {
                    @Override
                    public Flowable<T> apply(BaseCodeResponse<T> tBaseCodeResponse){
                        //如果返回结果没有data字段，需要抛出错误，createFlowable不允许传null
                        if("200".equals(tBaseCodeResponse.code) && tBaseCodeResponse.data != null) {
                            return createFlowable(tBaseCodeResponse.data);
                        }else {
                            return Flowable.error(new CustomException(tBaseCodeResponse.code,tBaseCodeResponse.msg));
                        }
                    }
                });
            }
        };
    }

    /**
     * 创建Flowable
     */

    private static <T>Flowable<T> createFlowable(final T t){
        return Flowable.create(new FlowableOnSubscribe<T>() {
            @Override
            public void subscribe(@NonNull FlowableEmitter<T> emitter) throws Exception {
                try {
                    emitter.onNext(t);
                    emitter.onComplete();
                }catch (Exception e){
                    emitter.onError(e);
                }
            }
        }, BackpressureStrategy.BUFFER);
    }

    public static class RetryWithDelay implements Function<Flowable<? extends Throwable>, Flowable<?>> {
        private final int maxRetries;
        private final int retryDelayMillis;
        private int retryCount;

        public RetryWithDelay(final int maxRetries, final int retryDelayMillis) {
            this.maxRetries = maxRetries;
            this.retryDelayMillis = retryDelayMillis;
            this.retryCount = 0;
        }



        @Override
        public Flowable<?> apply(Flowable<? extends Throwable> attempts) throws Exception {
            return attempts
                    .flatMap(new Function<Throwable, Flowable<?>>() {
                        @Override
                        public Flowable<?> apply(final Throwable throwable) {
                            if (++retryCount < maxRetries) {
                                // When this Observable calls onNext, the original
                                // Observable will be retried (i.e. re-subscribed).
                                return Flowable.timer(retryDelayMillis,
                                        TimeUnit.MILLISECONDS);
                            }

                            // Max retries hit. Just pass the error along.
                            return Flowable.error(throwable);
                        }
                    });
        }
    }
}
